﻿using System;
using System.Drawing;
using System.Windows.Forms;
using System.Runtime.InteropServices;

namespace TimedScreenSaver
{
    public partial class ScreenSaverForm : Form
    {
        #region Win32 API functions

        [DllImport("user32.dll")]
        static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent);

        [DllImport("user32.dll")]
        static extern int SetWindowLong(IntPtr hWnd, int nIndex, IntPtr dwNewLong);

        [DllImport("user32.dll", SetLastError = true)]
        static extern int GetWindowLong(IntPtr hWnd, int nIndex);

        [DllImport("user32.dll")]
        static extern bool GetClientRect(IntPtr hWnd, out Rectangle lpRect);

        #endregion

        #region Fields

        private const int MarginPosition = 100;
        private const int DateUnderTextInterval = 5;

        //private readonly Random _rand = new Random();
        private readonly bool _previewMode;
        private static readonly Point PreviewPoint = new Point(30,30);
        private static readonly Font PreviewFont = new Font("Arial", 8, FontStyle.Bold);

        private Point _mouseLocation;
        private bool _needMove;

        #endregion

        #region Properties

        public bool IsTestMode { get; set; }

        #endregion

        #region Constructors

        public ScreenSaverForm()
        {
            InitializeComponent();
        }

        public ScreenSaverForm(Rectangle bounds)
            : this()
        {
            Bounds = bounds;
        }

        public ScreenSaverForm(IntPtr previewWndHandle)
            : this()
        {

            // Set the preview window as the parent of this window
            SetParent(Handle, previewWndHandle);

            // Make this a child window so it will close when the parent dialog closes
            SetWindowLong(Handle, -16, new IntPtr(GetWindowLong(Handle, -16) | 0x40000000));

            // Place our window inside the parent
            Rectangle parentRect;
            GetClientRect(previewWndHandle, out parentRect);
            Size = parentRect.Size;
            Location = new Point(0, 0);

            // Make text smaller
            //contentLbl.Font = new Font("Arial", 6);

            _previewMode = true;
        }

        #endregion

        #region Methods
        
        private void LoadSettings()
        {
            if(!IsTestMode) Settings.Instance.LoadSettings();

            SetFont(_previewMode ? PreviewFont : Settings.Instance.FontText);
            SetFontColor(Settings.Instance.FontColor);
            SetBackColor(Settings.Instance.BackColor);

            if (Settings.Instance.IsTimeDisplayed)
            {
                UpdateContendAndDateText();
                screenTimer.Start();
            }
            else
            {
                contentLbl.Text = Settings.Instance.ContentText;
            }

            contentLbl.Location = _previewMode ? PreviewPoint : GetContentTextPosition();

            if(Settings.Instance.IsDateDisplayed)
            {
                dateLbl.Visible = true;
                dateLbl.Text = Settings.Instance.DateText;
                dateLbl.Location = GetDateTextPosition(contentLbl.Location);
            }
        }

        private Point GetContentTextPosition()
        {
            switch (Settings.Instance.PositionOnScreen)
            {
                case ScreenPosition.Custom:
                    return Settings.Instance.CustomScreenPosition;
                case ScreenPosition.TopLeft:
                    return new Point(MarginPosition, MarginPosition);
                case ScreenPosition.TopCenter:
                    return new Point((Width - contentLbl.Width) / 2, MarginPosition);
                case ScreenPosition.TopRight:
                    return new Point((Width - contentLbl.Width - MarginPosition), MarginPosition);
                case ScreenPosition.MidLeft:
                    return new Point(MarginPosition, (Height - contentLbl.Height) / 2);
                case ScreenPosition.MidRight:
                    return new Point((Width - contentLbl.Width - MarginPosition), (Height - contentLbl.Height) / 2);
                case ScreenPosition.BottLeft:
                    return new Point(MarginPosition, (Height - contentLbl.Height - MarginPosition));
                case ScreenPosition.BottCenter:
                    return new Point((Width - contentLbl.Width) / 2, (Height - contentLbl.Height - MarginPosition));
                case ScreenPosition.BottRight:
                    return new Point((Width - contentLbl.Width - MarginPosition), (Height - contentLbl.Height - MarginPosition));
                //case ScreenPosition.MidCenter:
                default:
                    return new Point((Width - contentLbl.Width) / 2, (Height - contentLbl.Height) / 2);
            }
        }

        private Point GetDateTextPosition(Point contentPoint)
        {
            int lenDiff = Math.Abs(dateLbl.Width - contentLbl.Width) / 2;
            int xPos;
            if (contentLbl.Width < dateLbl.Width)
            {
                xPos = contentPoint.X - lenDiff;
            }
            else
            {
                xPos = contentPoint.X + lenDiff;
            }

            return new Point(xPos, contentPoint.Y + contentLbl.Height + DateUnderTextInterval);
        }

        private void SetBackColor(Color backColor)
        {
            contentLbl.BackColor = IsTestMode ? Color.White : backColor;
            dateLbl.BackColor = IsTestMode ? Color.White : backColor;
            BackColor = backColor;
        }

        private void SetFontColor(Color fontColor)
        {
            contentLbl.ForeColor = fontColor;
            dateLbl.ForeColor = fontColor;
        }

        private void SetFont(Font newFont)
        {
            contentLbl.Font = newFont;
            dateLbl.Font = new Font(newFont.FontFamily, newFont.Size / Settings.Instance.DateFontSizeFactor, GraphicsUnit.Point);
        }

        #region Handlers

        private void ScreenSaverFormLoad(object sender, EventArgs e)
        {
            LoadSettings();

            if (!IsTestMode) Cursor.Hide();
        }

        private void TimerTick(object sender, EventArgs e)
        {
            // Move text to new location
            //textLabel.Left = _rand.Next(Math.Max(1, Bounds.Width - textLabel.Width));
            //textLabel.Top = _rand.Next(Math.Max(1, Bounds.Height - textLabel.Height));

            UpdateContendAndDateText();
        }

        private void UpdateContendAndDateText()
        {
            contentLbl.Text = Settings.Instance.TimeText;
            if (dateLbl.Visible)
            {
                dateLbl.Text = Settings.Instance.DateText;
            }
        }

        private void ScreenSaverFormMouseMove(object sender, MouseEventArgs e)
        {
            if (!_previewMode && !IsTestMode)
            {
                if (!_mouseLocation.IsEmpty)
                {
                    // Terminate if mouse is moved a significant distance
                    if (Math.Abs(_mouseLocation.X - e.X) > 5 ||
                        Math.Abs(_mouseLocation.Y - e.Y) > 5)
                        Application.Exit();
                }

                // Update current mouse location
                _mouseLocation = e.Location;
            }
        }

        private void ScreenSaverFormKeyPress(object sender, KeyPressEventArgs e)
        {
            if (!_previewMode)
            {
                if(IsTestMode) Close();
                else Application.Exit();
            }
        }

        private void ScreenSaverFormMouseClick(object sender, MouseEventArgs e)
        {
            if (!_previewMode && !IsTestMode)
            {
                Application.Exit();
            }
        }
        
        private void ContentLblMouseDown(object sender, MouseEventArgs e)
        {
            if (IsTestMode)
            {
                if (e.Button == MouseButtons.Left)
                {
                    _mouseLocation = e.Location;
                    _needMove = true;
                }
            }
        }

        private void ContentLblMouseMove(object sender, MouseEventArgs e)
        {
            if (IsTestMode)
            {
                if (_needMove)
                {
                    contentLbl.Left = contentLbl.Left + e.X - _mouseLocation.X;
                    contentLbl.Top = contentLbl.Top + e.Y - _mouseLocation.Y;

                    if (Settings.Instance.IsDateDisplayed)
                    {
                        dateLbl.Location = GetDateTextPosition(contentLbl.Location);
                    }
                }
            }
        }

        private void ContentLblMouseUp(object sender, MouseEventArgs e)
        {
            if (IsTestMode)
            {
                _needMove = false;
                _mouseLocation = Point.Empty;
                Settings.Instance.CustomScreenPosition = contentLbl.Location;

                Close();
            }
        }

        #endregion

        #endregion
    }
}
